﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.Serialization;


namespace MishraReader.Entities
{
    [DataContract]
    [DebuggerDisplay("Label = {Label}, Unread = {UnreadCount}, IsFeed = {IsFeed}")]
    public class SubscriptionCategory : Notifier, IEquatable<SubscriptionCategory>, IGoogleReaderStream
    {
        private ObservableCollection<Subscription> _subscriptions;
        private Dictionary<Subscription, PropertyObserver<Subscription>> _observers;
        private int _unreadCount;

        public SubscriptionCategory(SubscriptionsList list)
        {
            UnreadCount = 0;
            OnDeserialized(default(StreamingContext));
        }

        public bool HasItems
        {
            get { return Subscriptions.Any(s => s.HasItems); }
        }

        public bool HasStarred
        {
            get { return Subscriptions.Any(s => s.HasStarred); }
        }

        public bool HasUnreads
        {
            get { return UnreadCount > 0; }
        }


        public bool IsFeed { get; set; }

        [DataMember(Name = "id")]
        public string Id { get; set; }

        [DataMember(Name = "label")]
        public string Label { get; set; }


        public IEnumerable<Subscription> Subscriptions
        {
            get { return _subscriptions; }
        }

        public int UnreadCount
        {
            get { return _unreadCount; }
            set
            {
                Set(ref _unreadCount, value);
                RaisePropertyChanged(() => HasUnreads);
            }
        }

        public bool Equals(SubscriptionCategory other)
        {
            if (ReferenceEquals(null, other)) return false;
            if (ReferenceEquals(this, other)) return true;
            return IsFeed == other.IsFeed && 
                   Equals(other.Label, Label);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != typeof(SubscriptionCategory)) return false;
            return Equals((SubscriptionCategory)obj);
        }

        public override int GetHashCode()
        {
            return IsFeed.GetHashCode() ^ (Label != null ? Label.GetHashCode() : 0);
        }

        public override string ToString()
        {
            return string.Format("Label = {0}, Unread = {1}", Label, UnreadCount);
        }

        internal void AddSubscription(Subscription subscription)
        {
            if (Subscriptions.Contains(subscription))
                return;

            _subscriptions.Add(subscription);

            var obs = PropertyObserver.Create(subscription);
            _observers[subscription] = obs;

            obs.RegisterHandler(o => o.UnreadsCount, _ => RaiseUnreadsCountChanged());
        }

        private void RaiseUnreadsCountChanged()
        {
            UnreadCount = Subscriptions.Sum(s => s.UnreadsCount);

            //Debug.WriteLine(Label + " " + UnreadCount);

            RaisePropertyChanged(() => UnreadCount);
            RaisePropertyChanged(() => HasUnreads);
        }

        internal void RemoveSubscription(Subscription subscription)
        {
            _subscriptions.Remove(subscription);

            PropertyObserver<Subscription> obs;
            if(_observers.TryGetValue(subscription, out obs))
            {
                obs.UnregisterAllHandlers();
                _observers.Remove(subscription);
            }
        }

        [OnDeserialized]
        private void OnDeserialized(StreamingContext c)
        {
            _subscriptions = new ObservableCollection<Subscription>();
            _observers = new Dictionary<Subscription, PropertyObserver<Subscription>>();
        }

        public static bool operator ==(SubscriptionCategory left, SubscriptionCategory right)
        {
            return Equals(left, right);
        }

        public static bool operator !=(SubscriptionCategory left, SubscriptionCategory right)
        {
            return !Equals(left, right);
        }
    }
}